package cn.com.anypay.manager.service;

import cn.com.anypay.manager.dto.config.WeChatAuthConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.LocalDateTime;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * 微信网络健康检查服务
 * 负责检查与微信API服务器的网络连通性和健康状态
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WeChatNetworkHealthChecker {
    
    @Qualifier("weChatRestTemplate")
    private final RestTemplate weChatRestTemplate;
    private final WeChatAuthConfig weChatAuthConfig;
    
    // 健康检查结果缓存
    private volatile HealthCheckResult lastHealthCheckResult;
    private volatile LocalDateTime lastHealthCheckTime;
    
    /**
     * 执行完整的网络健康检查
     * 
     * @return 健康检查结果
     */
    public HealthCheckResult performHealthCheck() {
        log.info("开始执行微信API网络健康检查");
        
        HealthCheckResult result = new HealthCheckResult();
        result.setCheckTime(LocalDateTime.now());
        
        try {
            // 1. DNS解析检查
            boolean dnsResolved = checkDnsResolution();
            result.setDnsResolved(dnsResolved);
            
            // 2. 网络连通性检查
            boolean networkReachable = checkNetworkReachability();
            result.setNetworkReachable(networkReachable);
            
            // 3. API端点可用性检查
            boolean apiAvailable = checkApiAvailability();
            result.setApiAvailable(apiAvailable);
            
            // 4. 响应时间检查
            long responseTime = measureResponseTime();
            result.setResponseTime(responseTime);
            
            // 综合评估健康状态
            boolean isHealthy = dnsResolved && networkReachable && apiAvailable && responseTime < 10000;
            result.setHealthy(isHealthy);
            
            // 缓存结果
            this.lastHealthCheckResult = result;
            this.lastHealthCheckTime = LocalDateTime.now();
            
            log.info("微信API网络健康检查完成 - 状态: {}, DNS: {}, 网络: {}, API: {}, 响应时间: {}ms", 
                    isHealthy ? "健康" : "异常", dnsResolved, networkReachable, apiAvailable, responseTime);
            
            return result;
            
        } catch (Exception e) {
            log.error("微信API网络健康检查失败", e);
            result.setHealthy(false);
            result.setErrorMessage(e.getMessage());
            return result;
        }
    }
    
    /**
     * 异步执行健康检查
     * 
     * @return 健康检查结果的Future
     */
    public CompletableFuture<HealthCheckResult> performHealthCheckAsync() {
        return CompletableFuture.supplyAsync(this::performHealthCheck);
    }
    
    /**
     * 检查DNS解析
     * 
     * @return DNS是否可以正常解析
     */
    private boolean checkDnsResolution() {
        try {
            String host = extractHostFromUrl(weChatAuthConfig.getTokenUrl());
            InetAddress address = InetAddress.getByName(host);
            log.debug("DNS解析成功: {} -> {}", host, address.getHostAddress());
            return true;
        } catch (UnknownHostException e) {
            log.warn("DNS解析失败: {}", e.getMessage());
            return false;
        }
    }
    
    /**
     * 检查网络连通性
     * 
     * @return 网络是否可达
     */
    private boolean checkNetworkReachability() {
        try {
            String host = extractHostFromUrl(weChatAuthConfig.getTokenUrl());
            InetAddress address = InetAddress.getByName(host);
            boolean reachable = address.isReachable(5000); // 5秒超时
            log.debug("网络连通性检查: {} - {}", host, reachable ? "可达" : "不可达");
            return reachable;
        } catch (Exception e) {
            log.warn("网络连通性检查失败: {}", e.getMessage());
            return false;
        }
    }
    
    /**
     * 检查API端点可用性
     * 通过发送一个简单的HTTP请求来检查API是否可用
     * 
     * @return API是否可用
     */
    private boolean checkApiAvailability() {
        try {
            // 构造一个简单的测试URL（不需要有效参数，只检查服务器响应）
            String testUrl = weChatAuthConfig.getTokenUrl() + "?test=1";
            
            ResponseEntity<String> response = weChatRestTemplate.exchange(
                    testUrl, HttpMethod.GET, null, String.class);
            
            // 即使返回错误状态码，只要服务器有响应就认为API可用
            boolean available = response.getStatusCode() != HttpStatus.SERVICE_UNAVAILABLE;
            log.debug("API可用性检查: 状态码 {} - {}", response.getStatusCode(), available ? "可用" : "不可用");
            return available;
            
        } catch (Exception e) {
            log.warn("API可用性检查失败: {}", e.getMessage());
            return false;
        }
    }
    
    /**
     * 测量API响应时间
     * 
     * @return 响应时间（毫秒）
     */
    private long measureResponseTime() {
        long startTime = System.currentTimeMillis();
        
        try {
            String testUrl = weChatAuthConfig.getTokenUrl() + "?test=1";
            weChatRestTemplate.exchange(testUrl, HttpMethod.GET, null, String.class);
            
        } catch (Exception e) {
            // 即使请求失败，也记录响应时间
            log.debug("响应时间测量过程中发生异常（这是正常的）: {}", e.getMessage());
        }
        
        long responseTime = System.currentTimeMillis() - startTime;
        log.debug("API响应时间: {}ms", responseTime);
        return responseTime;
    }
    
    /**
     * 从URL中提取主机名
     * 
     * @param url 完整URL
     * @return 主机名
     */
    private String extractHostFromUrl(String url) {
        try {
            return new java.net.URL(url).getHost();
        } catch (Exception e) {
            log.warn("无法从URL提取主机名: {}", url);
            return "api.weixin.qq.com"; // 默认微信API主机
        }
    }
    
    /**
     * 获取最后一次健康检查结果
     * 
     * @return 健康检查结果，如果从未检查过则返回null
     */
    public HealthCheckResult getLastHealthCheckResult() {
        return lastHealthCheckResult;
    }
    
    /**
     * 获取最后一次健康检查时间
     * 
     * @return 检查时间，如果从未检查过则返回null
     */
    public LocalDateTime getLastHealthCheckTime() {
        return lastHealthCheckTime;
    }
    
    /**
     * 检查是否需要重新进行健康检查
     * 
     * @param maxAgeMinutes 最大缓存时间（分钟）
     * @return 是否需要重新检查
     */
    public boolean needsHealthCheck(int maxAgeMinutes) {
        if (lastHealthCheckTime == null) {
            return true;
        }
        
        LocalDateTime threshold = LocalDateTime.now().minusMinutes(maxAgeMinutes);
        return lastHealthCheckTime.isBefore(threshold);
    }
    
    /**
     * 快速健康检查（使用缓存结果）
     * 
     * @return 是否健康
     */
    public boolean isHealthy() {
        if (needsHealthCheck(5)) { // 5分钟内的结果有效
            performHealthCheck();
        }
        
        return lastHealthCheckResult != null && lastHealthCheckResult.isHealthy();
    }
    
    /**
     * 健康检查结果类
     */
    public static class HealthCheckResult {
        private LocalDateTime checkTime;
        private boolean healthy;
        private boolean dnsResolved;
        private boolean networkReachable;
        private boolean apiAvailable;
        private long responseTime;
        private String errorMessage;
        
        // Getters and Setters
        public LocalDateTime getCheckTime() {
            return checkTime;
        }
        
        public void setCheckTime(LocalDateTime checkTime) {
            this.checkTime = checkTime;
        }
        
        public boolean isHealthy() {
            return healthy;
        }
        
        public void setHealthy(boolean healthy) {
            this.healthy = healthy;
        }
        
        public boolean isDnsResolved() {
            return dnsResolved;
        }
        
        public void setDnsResolved(boolean dnsResolved) {
            this.dnsResolved = dnsResolved;
        }
        
        public boolean isNetworkReachable() {
            return networkReachable;
        }
        
        public void setNetworkReachable(boolean networkReachable) {
            this.networkReachable = networkReachable;
        }
        
        public boolean isApiAvailable() {
            return apiAvailable;
        }
        
        public void setApiAvailable(boolean apiAvailable) {
            this.apiAvailable = apiAvailable;
        }
        
        public long getResponseTime() {
            return responseTime;
        }
        
        public void setResponseTime(long responseTime) {
            this.responseTime = responseTime;
        }
        
        public String getErrorMessage() {
            return errorMessage;
        }
        
        public void setErrorMessage(String errorMessage) {
            this.errorMessage = errorMessage;
        }
        
        @Override
        public String toString() {
            return String.format("HealthCheckResult{检查时间=%s, 健康状态=%s, DNS解析=%s, 网络连通=%s, API可用=%s, 响应时间=%dms, 错误信息='%s'}", 
                    checkTime, healthy, dnsResolved, networkReachable, apiAvailable, responseTime, errorMessage);
        }
    }
}